import fs from 'fs';
import path from 'path';
import glob from 'fast-glob';
import { REPO_BRANCH, REPO_PATH, docRoot, docsDirName, projRoot } from './constants';
import footer from './footer.json';

import type { Plugin } from 'vite';

type Append = Record<'headers' | 'footers' | 'scriptSetups', string[]>;

export function MarkdownTransform(): Plugin {
  return {
    name: 'element-plus-md-transform',
    enforce: 'pre',
    async transform(code, id) {
      if (!id.endsWith('.md')) return;

      // if (path.normalize(id) === path.normalize(docRoot + '/index.md')) {
      //   return code;
      // }

      const componentId = path.basename(id, '.md');
      const append: Append = {
        headers: [],
        footers: [],
        scriptSetups: [`const demos = import.meta.globEager('../examples/${componentId}/*.vue')`],
      };

      code = transformVpScriptSetup(code, append);

      const pattern = `/component/`;
      const compPaths = await glob(pattern, {
        cwd: docRoot,
        absolute: true,
        onlyDirectories: true,
      });

      if (compPaths.some((compPath) => id.startsWith(compPath))) {
        code = transformComponentMarkdown(id, componentId, code, append);
      }

      return combineMarkdown(code, [combineScriptSetup(append.scriptSetups), ...append.headers], append.footers);
    },
  };
}

const combineScriptSetup = (codes: string[]) =>
  `\n<script setup>
${codes.join('\n')}
</script>
`;

const combineMarkdown = (code: string, headers: string[], footers: string[]) => {
  const frontmatterEnds = code.indexOf('---\n\n') + 4;
  const firstSubheader = code.search(/\n## \w/);
  const sliceIndex = firstSubheader < 0 ? frontmatterEnds : firstSubheader;

  if (headers.length > 0) code = code.slice(0, sliceIndex) + headers.join('\n') + code.slice(sliceIndex);
  code += footers.join('\n');

  return `${code}\n`;
};

const vpScriptSetupRE = /<vp-script\s(.*\s)?setup(\s.*)?>([\s\S]*)<\/vp-script>/;

const transformVpScriptSetup = (code: string, append: Append) => {
  const matches = code.match(vpScriptSetupRE);
  if (matches) code = code.replace(matches[0], '');
  const scriptSetup = matches?.[3] ?? '';
  if (scriptSetup) append.scriptSetups.push(scriptSetup);
  return code;
};

const GITHUB_BLOB_URL = `https://github.com/${REPO_PATH}/blob/${REPO_BRANCH}`;
const GITHUB_TREE_URL = `https://github.com/${REPO_PATH}/tree/${REPO_BRANCH}`;
const transformComponentMarkdown = (id: string, componentId: string, code: string, append: Append) => {
  const docUrl = `${GITHUB_BLOB_URL}/${docsDirName}/component/${componentId}.md`;
  const componentUrl = `${GITHUB_TREE_URL}/packages/components/${componentId}`;
  const componentPath = path.resolve(projRoot, `packages/components/${componentId}`);
  const isComponent = fs.existsSync(componentPath);

  const links = [[footer.docs, docUrl]];
  if (isComponent) links.unshift([footer.component, componentUrl]);
  const linksText = links
    .filter((i) => i)
    .map(([text, link]) => `[${text}](${link})`)
    .join(' • ');

  const sourceSection = `
## ${footer.source}

${linksText}
`;

  const contributorsSection = `
## ${footer.contributors}

<Contributors id="${componentId}" />
`;

  append.footers.push(sourceSection, isComponent ? contributorsSection : '');

  return code;
};
